package com.example.coupon.executor.impl;

import com.alibaba.fastjson.JSON;
import com.example.coupon.constant.CouponCategory;
import com.example.coupon.constant.RuleFlag;
import com.example.coupon.executor.AbstractExecutor;
import com.example.coupon.executor.RuleExecutor;
import com.example.coupon.vo.GoodsInfo;
import com.example.coupon.vo.SettlementInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 满减+折扣优惠券结算规则执行器
 *
 * @author wangbo
 * @description:
 * @date 2021/2/2011:39
 */
@Slf4j
@Component
public class ManJianZheKouExecutor extends AbstractExecutor implements RuleExecutor {

    @Override
    public RuleFlag ruleConfig() {
        return RuleFlag.MANJIAN_ZHEKOU;
    }

    /**
     * @param settlement {@link SettlementInfo} 用户传递的计算信息
     * @return
     */
    @Override
    protected boolean isGoodsTypeSatisfy(SettlementInfo settlement) {
        log.debug("Check ManJian And ZheKou Is Match Or Not!");
        List<Integer> goodsType = settlement.getGoodsInfos().stream().map(GoodsInfo::getType).collect(Collectors.toList());

        List<Integer> templateGoodsType = new ArrayList<>();

        settlement.getCouponAndTemplateInfos().forEach(ct -> {
            templateGoodsType.addAll(JSON.parseObject(ct.getTemplate().getTemplateRule().getUsage().getGoodsType(), List.class));
        });

        //如果想要使用多类优惠券，则必须要所有的商品类型都包含在内，即差集为空
        return CollectionUtils.isEmpty(CollectionUtils.subtract(goodsType, templateGoodsType));
    }

    @Override
    public SettlementInfo computeRule(SettlementInfo settlement) {
        double goodsSum = retain2Decimals(goodsCostSum(settlement.getGoodsInfos()));

        SettlementInfo probability = processGoodsTypeNotSatisfy(settlement, goodsSum);
        if (null != probability) {
            log.debug("ManJian And ZheKou Template Is Not Match To GoodsType!");
            return probability;
        }

        SettlementInfo.CouponAndTemplateInfo manJian = null;
        SettlementInfo.CouponAndTemplateInfo zhekou = null;

        for (SettlementInfo.CouponAndTemplateInfo ct : settlement.getCouponAndTemplateInfos()) {
            if (CouponCategory.of(ct.getTemplate().getCategory()) == CouponCategory.MANJIAN) {
                manJian = ct;
            } else {
                zhekou = ct;
            }
        }

        assert null != manJian;
        assert null != zhekou;

        //当前的优惠券和满减券如果不能共用（一起使用），清空优惠券，返回商品原价
        if (!isTemplateCanShared(manJian, zhekou)) {
            log.debug("Current Manjian And Zhekou Can Not Shared!");
            settlement.setCost(goodsSum);
            settlement.setCouponAndTemplateInfos(Collections.emptyList());
            return settlement;
        }

        List<SettlementInfo.CouponAndTemplateInfo> ctInfos = new ArrayList<>();
        double manjianBase = (double) manJian.getTemplate().getTemplateRule().getDiscount().getBase();
        double manjianQuota = (double) manJian.getTemplate().getTemplateRule().getDiscount().getQuota();

        //最终的价格
        double targetSum = goodsSum;

        //先计算满减 再计算折扣
        if (targetSum >= manjianBase) {
            targetSum -= manjianQuota;
            ctInfos.add(manJian);
        }

        //再计算折扣
        double zhekouQuota = (double) zhekou.getTemplate().getTemplateRule().getDiscount().getQuota();
        targetSum *= zhekouQuota * 1.0 / 100;
        ctInfos.add(zhekou);

        settlement.setCouponAndTemplateInfos(ctInfos);
        settlement.setCost(retain2Decimals(targetSum>minCost()?targetSum:minCost()));

        log.debug("Use Manjian And Zhekou Coupon Make Goods Cost From {} To {}",goodsSum,settlement.getCost());
        return settlement;
    }

    /**
     * 当前的两张优惠券是否可以共用
     * 即校验TemplateRule中的weight 是否满足条件
     *
     * @param manJian
     * @param zheKou
     * @return
     */
    private boolean isTemplateCanShared(SettlementInfo.CouponAndTemplateInfo manJian, SettlementInfo.CouponAndTemplateInfo zheKou) {
        String manjianKey = manJian.getTemplate().getKey() + String.format("%04d", manJian.getTemplate().getId());
        String zhekouKey = zheKou.getTemplate().getKey() + String.format("%04d", zheKou.getTemplate().getId());

        List<String> allSharedKeysForManjian = new ArrayList<>();
        allSharedKeysForManjian.add(manjianKey);
        allSharedKeysForManjian.addAll(JSON.parseObject(manJian.getTemplate().getTemplateRule().getWeight(), List.class));

        List<String> allSharedKeysForZhekou = new ArrayList<>();
        allSharedKeysForZhekou.add(zhekouKey);
        allSharedKeysForZhekou.addAll(JSON.parseObject(zheKou.getTemplate().getTemplateRule().getWeight(), List.class));
        return CollectionUtils.isSubCollection(Arrays.asList(manjianKey, zhekouKey), allSharedKeysForManjian)
                || CollectionUtils.isSubCollection(Arrays.asList(manjianKey, zhekouKey), allSharedKeysForZhekou);
    }
}
